/***
 * 时间工厂：
 * 1.生产计时器和倒计时器（倒计时的时间到了是可以停止的,不过计时器是不能自动停止的）
 * 2.判断是否有CD时间,创建游戏时间,测试程序运行使用时间
 * 单位是：秒
 * 计时器：let timer=TimeFactory.createTime('keyName','up');
 * 倒计时：let timer=TimeFactory.createTime('keyName','down');
 * 倒计时时默认为'down'如TimeFactory.createTime('keyName');
 * 设置回调函数：timer.setBackFunction((data)=>{});
 * 设置起始时间：timer.time=100;
 * 开始循环执行：timer.start();
 * 停止执行：timer.stop();
 * 设置起始并开始：timer.setTimeStart(100);
 * 快速设置倒计时：TimeFactory.createDownTime('keyName',100,(data)=>{console.log(data)});
 * 快速设置计时器：TimeFactory.createUpTime('keyName',100,(data)=>{console.log(data)});
 * 快速设置毫秒计时器：TimeFactory.createUpMillisecond('keyName',100,(data)=>{console.log(data)});
 * 快速设置毫秒倒计时器：TimeFactory.createDownMillisecond('keyName',100,(data)=>{console.log(data)});
 * 删除时间：TimeFactory.removeTime('keyName');
 * 得到时间：TimeFactory.getContentTime('keyName');
 * 是否有CD时间：TimeFactory.hasCdTime('keyName',3,'');
 * 创建游戏时间：TimeFactory.createGameTime('keyName',this.update.bind(this));//默认是60帧每秒,不使用精确计算（可通过isPrecise修改）
 * 使用时间：TimeFactory.useTime('keyName',0)//0开始计时,1结束计时,返回的是毫秒
 * 时间格式化：TimeFactory.formatTime(361,1)//'6分1秒' TimeFactory.formatTime(361,0)//6:01
 * 时间格式化：showNum为3时00:00:00(时:分:秒),为2时00:00(分:秒),为1时00(秒)
 * 注意了每个keyName都不能相同
 * author:ywx620
 * web:https://ywx620.gitee.io/learn/
 */
const TimeFactory = function (exports) {
    const content={};
    const COUNT_DOWN='down';
    const COUNT_UP='up';
    const COUNT_DOWN_M='millisecond_down';
    const COUNT_UP_M='millisecond_up';
    /**创建开始计时或倒计时*/
    const createTime = (name, type = "down") => {
        if (content[name] == null) { //如果工厂仓库中没有找到同标签的产品,那么生产新产品
            var timer;
            if (type == COUNT_DOWN) { //创建倒计时产品
                timer = new TF_TimeCountDown();
            } else if (type == COUNT_UP) { //创建计时器产品
                timer = new TF_TimeCountUp();
            }else if(type==COUNT_UP_M){
                timer=new TF_MillisecondCountUp();
            }else if(type==COUNT_DOWN_M){
                timer=new TF_MillisecondCountDown();
            }
            timer.name = name; //给产品标个签名
            content[name] = timer; //把产品放入工厂仓库中
        }
        return content[name];
    }
    /**创建倒计时,时间单位秒,isLoop为true时每秒都调用（每秒回调有参数，时间到才调无参数）*/
    const createDownTime = (name, time, callBack, isLoop = true,showNum=2) => {
        var timer = createTime(name,COUNT_DOWN);
        timer.showNum=showNum;
        timer.setBackFunction((data) => {
            if (callBack) {
                if(isLoop)                  callBack(data)//每秒都会调用
                else if(data.value == 0)    callBack()//时间到才调用
            }
        });
        timer.setTimeStart(time);
        return timer;
    }
    /**计时器,时间单位秒*/
    const createUpTime = (name, time, callBack,showNum=2) => {
        var timer = createTime(name,COUNT_UP);
        timer.showNum=showNum;
        timer.setBackFunction((data) => {
            if (callBack) {
                callBack(data);
            }
        });
        timer.setTimeStart(time);
        return timer;
    }
    /**计时器毫秒单位*/
    const createUpMillisecond = (name, time, callBack,showNum=2) => {
        var timer = createTime(name,COUNT_UP_M);
        timer.interval=1000/60;
        timer.showMil3=(showNum==3);
        timer.setBackFunction((data) => {
            if (callBack) {
                callBack(data);
            }
        });
        timer.setTimeStart(time);
        return timer;
    }
    /**倒计时器毫秒单位*/
    const createDownMillisecond = (name, time, callBack,showNum=2) => {
        var timer = createTime(name,COUNT_DOWN_M);
        timer.interval=1000/60;
        timer.showMil3=(showNum==3);
        timer.setBackFunction((data) => {
            if (callBack) {
                callBack(data);
            }
        });
        timer.setTimeStart(time);
        return timer;
    }
    /**创建游戏时间,默认是60每秒帧,不使用精确计算*/
    const createGameTime=(name,callBack,fps=60)=>{
        var timer=createTime(name,'up');
        timer.interval=1000/fps;
        timer.setBackFunction(()=>{callBack()})
        timer.start();
        timer.isPrecise=false;
        return timer;
    }
    /**找到时间产品然后销毁掉*/
    const removeTime = (name) => {
        var timer = content[name];
        if (timer) {
            timer.dispose();
            delete content[timer.name];
        }
        return null;
    }
    /**得到已经存在的时间产品*/
    const getContentTime = (name) => {
        var timer = content[name];
        if (timer) return timer;
        return null;
    }
    /**查看是否有CD时间（返回true/false）-使用场景（如，按钮1秒内只能点击一次）不想有提示参数tip传null或''*/
    const hasCdTime=(name,time=3,tip='请稍后再点')=>{
        var timer=getContentTime(name);
        if(timer&&timer.time>0){//还有CD时间
            if(!!tip){
                if(tip.indexOf('num')>=0)tip=tip.replace('num',timer.time);
                alert(tip);
            }
            return true;
        }else{//没有CD时间了
            createTime(name).setTimeStart(time);
            return false;
        }
    }
    /**使用了多长时间,开始传type=0,后传type=1,返回的是毫秒，回调函数的参数也是毫秒*/
    const useTime=(name,type=0,callBack=null,tip='使用了num秒')=>{
        if(type==0){
            removeTime(name);
            let timer=createTime(name);
            timer.stop();
            timer.data={start:(new Date().getTime())};
        }else{
            let timer=getContentTime(name);
            if(timer){
                var end=(new Date().getTime());
                var num=end-timer.data.start;
                if(callBack) callBack(num);
                if(!!tip){
                    if(tip.indexOf('num')>=0)tip=tip.replace('num',Math.ceil(num/1000));
                    alert(tip);
                }
                removeTime(name);
                return num;
            }
        }
    }
    /**格式化时间
     * second为秒数
     * type=0时格式23:59:59
     * type=1时格式23时59分8秒
     * showNum为3时00:00:00(时:分:秒),为2时00:00(分:秒),为1时00(秒)*
    */
    const formatTime=(second,type=0,showNum = 2)=>{
        let timer=new TF_TimeCountDown();//为了使用内部方法
        let value=timer.getTimeFormatByNum(second,':',showNum);
        if(type==0){//格式23:59:59
            return value;
        }else{//格式23时59分8秒
            let vs=value.split(':');
            let len=vs.length;
            if(len==1)      return `${parseInt(vs[0])}秒`;
            else if(len==2) return `${parseInt(vs[0])}分${parseInt(vs[1])}秒`;
            else if(len==3) return `${parseInt(vs[0])}时${parseInt(vs[1])}分${parseInt(vs[2])}秒`;
        }
    }
    //----时间类-----
    class TF_Timer {
        updateTime;
        isPlay = false;
        startTime=0;
        interval=1000;//间隔时间
        count=0;
        keyName;
        isPrecise=true;//是否精确
        start() {
            if(!this.isPlay){
                this.isPlay = true;
                this.startTime=new Date().getTime();
                this.count=0;
                this.update();
            }
        }
        stop() {
            this.isPlay = false;
            clearTimeout(this.keyName);
        }
        update() {
            if (this.isPlay) {
                if(this.isPrecise){//精确
                    let [interval,startTime,count]=[this.interval,this.startTime,this.count];
                    let offset = new Date().getTime() - (startTime + count * interval);//获得阻塞时间
                    let nextTime = interval - offset;//下次时间，需要扣除阻塞时间,setTimeout有个默认最小时间是4，当小于这个值就会变为4
                    //console.log(nextTime)//当线程被占用后，就有阻塞时间，下次再运行时间时就要变短了。所以不使用1000改用nextTime;
                    this.keyName = setTimeout(this.update.bind(this), nextTime);//使用nextTime就可以比较精准模拟计时与倒计时
                    this.count++;
                }else{//不精确
                    this.keyName = setTimeout(this.update.bind(this), this.interval);
                }
                if (this.updateTime)this.updateTime();
            }
        }
    }
    //----抽象时间类-----
    class TF_TimeAbstract {
        _time = 0;
        _name;
        _showNum = 2;
        data;
        backfunction;
        timer;
        name;
        removeTime() {
            if (this.timer) {
                this.timer.stop();
                this.timer = null;
            }
        }
        createTime() {
            this.removeTime();
            this.timer = new TF_Timer();
            this.timer.updateTime = this.onTimer.bind(this);
        }
        /**把数字转换成时间格式,showNum为3时00:00:00(时:分:秒),为2时00:00(分:秒),为1时00(秒)*/
        getTimeFormatByNum(num, type = ":", showNum = 2) {
            var hour;
            var minute;
            var second;
            if (showNum == 1) {
                second = this.numberFormat(num);
                return second;
            } else if (showNum == 2) {
                minute = this.numberFormat((num / 60));
                second = this.numberFormat(num % 60);
                return minute + type + second;
            } else if (showNum == 3) {
                hour = this.numberFormat(num / 60 / 60 >> 0);
                minute = this.numberFormat((num / 60) % 60);
                second = this.numberFormat(num % 60);
                return hour + type + minute + type + second;
            }
        }
        /**数字格式，把小于10的数在前面加个0*/
        numberFormat(num) {
            num = parseInt(num);
            if (num >= 10)
                return String(num);
            else
                return "0" + num;
        }
        /**此方法必须被子类重写*/
        onTimer() {
            throw new Error("抽像类不能实例化,必须使用子类实例化")
        }
        /**设置开始计时并且开始计时 value是单位是秒*/
        setTimeStart(value) {
            this.time = value;
            this.start();
        }
        /**开始计时*/
        start() {
            if (this.timer) this.timer.start();
            else this.showError();
        }
        stop() {
            if (this.timer)  this.timer.stop();
            else this.showError();
        }
        reset(value){
            this.time = value;
        }
        /**计时间隔，默认是1000毫秒*/
        set interval(value){
            if (this.timer) this.timer.interval=value;
            else this.showError();
        }
        /**是不是精确计时*/
        set isPrecise(value){
            if (this.timer) this.timer.isPrecise=value;
            else this.showError();
        }
        /**是不是精确计时对毫秒计时不起作用*/
        setPrecise(value){
            this.isPrecise=value;
        }
        showError(){
            console.error('timer已经无效,请调用createTime方法重新创建')
        }
        get time() {
            return this._time;
        }
        /**设置开始计时*/
        set time(value) {
            this._time = value;
        }
        /**表示显示几组数,1(00),2(00:00),3(00:00:00)*/
        get showNum() {
            return this._showNum;
        }
        set showNum(value) {
            this._showNum = value;
        }
        setBackFunction(value) {
            this.backfunction = value;
        }
        get name() {
            return this._name;
        }
    
        set name(value) {
            this._name = value;
        }
        /**{value:value,show:show}*/
        get timeData() {
            return this.data;
        }
        dispose() {
            this.removeTime();
        }
    }
    //---倒计时类------
    class TF_TimeCountDown extends TF_TimeAbstract{
        constructor() {
            super();
            this.createTime();
        }
        onTimer() {
            var show = this.getShow();
            var value = this._time--;
            if (value <= 0) {
                this.stop();
                this._time = 0;
                value=0;
            }
            this.data = {
                value: value,
                show: show
            }
            if (this.backfunction != null) {
                this.backfunction(this.data);
            }
        }
        getShow() {
            return this.getTimeFormatByNum(this._time, ":", this._showNum);
        }
    }
    //----计时器类-----
    class TF_TimeCountUp extends TF_TimeCountDown{
        onTimer() {
            var show = this.getShow();
            var value = this._time++;
            this.data = {
                value: value,
                show: show
            }
            if (this.backfunction != null) {
                this.backfunction(this.data);
            }
        }
    }
    //----毫秒计时器类-----
    class TF_MillisecondCountUp extends TF_TimeCountDown{
        /**设置开始计时并且开始计时 value是单位是秒*/
        setTimeStart(value) {
            this.time = value;
            this.startTime=(new Date).getTime();
            this.start();
        }
        countTime(){
            return (new Date).getTime()-this.startTime;
        }
        onTimer() {
            this._time=this.countTime();
            var show = this.getShow();
            var value = this._time;
            this.data = {
                value: value,
                show: show
            }
            if (this.backfunction != null) {
                this.backfunction(this.data);
            }
        }
        getTimeFormatByNum(millisecond, type = ":") {
            var num=parseInt(millisecond/1000);
            var minute = this.numberFormat((num / 60) % 60);
            var second = this.numberFormat(num % 60);
            var milSec=this.numberFormat((millisecond-num*1000)/10);
            if(this.showMil3){
                milSec=parseInt(millisecond-num*1000);
                milSec=milSec<0?0:milSec;
                if(milSec<10)       milSec='00'+milSec;
                else if(milSec<100) milSec='0'+milSec;
            }
            return minute + type + second+ '.' + milSec;
        }
    }
    //----毫秒倒计时器类-----
    class TF_MillisecondCountDown extends TF_MillisecondCountUp{
        setTimeStart(value) {
           super.setTimeStart(value);
           this.staMilTime=value*1000;
        }
        countTime(){
            var t=(new Date).getTime()-this.startTime;
            return this.staMilTime-t;
        }
        onTimer() {
            this._time=this.countTime();
            var show = this.getShow();
            var value = this._time;
            if (value <= 0) {
                this.stop();
                this._time = 0;
                value=0;
            }
            this.data = {
                value: value,
                show: show
            }
            if (this.backfunction != null) {
                this.backfunction(this.data);
            }
        }
    }
    exports.content=content;
	exports.COUNT_DOWN=COUNT_DOWN;
    exports.COUNT_DOWN_M=COUNT_DOWN_M;
	exports.COUNT_UP=COUNT_UP;
	exports.COUNT_UP_M=COUNT_UP_M;
    exports.createTime = createTime;
	exports.createDownTime = createDownTime;
	exports.createUpTime = createUpTime;
    exports.createUpMillisecond = createUpMillisecond;
    exports.createDownMillisecond = createDownMillisecond;
	exports.removeTime = removeTime;
	exports.getContentTime = getContentTime;
	exports.hasCdTime = hasCdTime;
	exports.createGameTime = createGameTime;
	exports.useTime = useTime;
	exports.formatTime = formatTime;
    Object.defineProperty(exports, "__esModule", {
        value: true
    });
    return exports
}
({});